package _21_多线程juc.demo03_atomic;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.val;
import lombok.var;
import org.junit.Test;
import org.python.antlr.ast.Str;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicStampedReference;

import static java.util.concurrent.ThreadLocalRandom.current;

public class TestAtomicStampedRef {

    /**
     * 初始化 ref and stamp        new AtomicStampedReference<>(ref, stamp)
     * 修改 ref and stamp         compareAndSet()
     * 修改 stamp                 attemptStamp()
     */
    @Test
    public void test_01() {
        AtomicStampedReference<String> reference = new AtomicStampedReference<>("abc",1);
        System.out.println("reference.getReference() = " + reference.getReference());
        System.out.println("reference.getStamp() = " + reference.getStamp());
        System.out.println();

        // 同时修改  reference  and  stamp
        boolean q = reference.compareAndSet("abc", "def", 9,reference.getStamp()+1);
        System.out.println("q = " + q);
        System.out.println("reference.getReference() = " + reference.getReference());
        System.out.println("reference.getStamp() = " + reference.getStamp());
        System.out.println();

        boolean a = reference.compareAndSet("abc", "def", 1,reference.getStamp()+1);
        System.out.println("a = " + a);
        System.out.println("reference.getReference() = " + reference.getReference());
        System.out.println("reference.getStamp() = " + reference.getStamp());
        System.out.println();

        // 只修改  stamp
        boolean b = reference.attemptStamp("abc", reference.getStamp() + 1);
        System.out.println("b = " + b);
        System.out.println("reference.getReference() = " + reference.getReference());
        System.out.println("reference.getStamp() = "+reference.getStamp());
        System.out.println();

        boolean c = reference.attemptStamp("def", reference.getStamp() + 1);
        System.out.println("c = " + c);
        System.out.println("reference.getReference() = " + reference.getReference());
        System.out.println("reference.getStamp() = "+reference.getStamp());
        System.out.println();

        // 调用的 compareAndSet
        boolean d = reference.weakCompareAndSet("def","ccc",4, reference.getStamp()+1);
        System.out.println("d = " + d);
        System.out.println("reference.getReference() = "+reference.getReference());
        System.out.println("reference.getStamp() = "+reference.getStamp());
        System.out.println();

        boolean e = reference.weakCompareAndSet("def","ccc",3, reference.getStamp()+1);
        System.out.println("e = " + e);
        System.out.println("reference.getReference() = "+reference.getReference());
        System.out.println("reference.getStamp() = "+reference.getStamp());
        System.out.println();

        // get(holder[])  stamp 放在 holder[0], ref 直接返回
        String haha = reference.get(new int[1]);
        System.out.println("haha = " + haha);
        int[] arr = {71,72};
        System.out.println(Arrays.toString(arr));
        String haha2 = reference.get(arr);
        System.out.println("haha2 = " + haha2);
        System.out.println(Arrays.toString(arr));
    }

    @Test
    public void test02() {
        TestStu stu = new TestStu("张三", 0);
        AtomicStampedReference<TestStu> stuRef = new AtomicStampedReference<>(stu, 0);
        // 创建十个线程，每人给 10 元
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int[] holder = new int[1];
                    TestStu tmpStu = stuRef.get(holder);
                    TestStu newStu =  new TestStu(tmpStu.getName(), tmpStu.getAccount()+10);
                    if(stuRef.compareAndSet(tmpStu, newStu, holder[0],holder[0]+1)) {
                        System.out.println("stu = " + newStu);
                        System.out.println("getStamp = " + stuRef.getStamp());
                    } else {
                        System.out.println("fail");
                    }
                    try {
                        TimeUnit.MILLISECONDS.sleep(current().nextInt(20));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }


}





